<?php
namespace Twoir\System\Support;

/**
 * 两张表存放模型 both
 *
 * cighsen02 365182575
 * time: 2022.12.29
 * update: 2025.04.03
 */
trait BothTrait
{
	/**
     * 字段默认值类型
     *
     * @return array
    */
    public static function fieldType(): array
    {
        $default = array_replace(static::MYDEFAULT['pri'], static::MYDEFAULT['sec']);
        //字段类型
        array_walk($default, function(&$value){

            $value = null === $value || 0 === $value ? 'int' : 'string';

        });

        return $default;
    }

	/**
	 * 统计数量
	 *
	 * @param array $where = {key => val}
	 * @param string $index
	 * @return int
	 */
	public static function getCount(?array $where = [], string $index = 'pri'): int
	{
		global $empire, $dbtbpre;

		['where' => $str_where] = static::parseWhere($where, false);
		//默认值
		$index = null === $index || empty($index) ? 'pri' : $index;

		$sql = sprintf('SELECT count(*) as total FROM %s%s', $dbtbpre . static::TABLE[$index], $str_where);

		return (int)$empire->gettotal($sql);
	}

	/**
	 * 拉取一条数据
	 *
	 * @param array $where 键值数组 $field 值数组
	 * @param array $field
	 * @param string $groupby
	 * @param string $orderby
	 * @return array
	*/
	public static function getOne(array $where = [], array $field = ['*'], string $groupby = '', string $orderby = ''): array
	{
		$result = static::getList($where, $field, $groupby, $orderby, 1, 0);

	    return $result ? array_values($result)[0] : [];
	}

	/**
	 * 读取多条(列表), 只取主表
	 *
	 * @param array $where
	 * @param array $field
	 * @param string $groupby
	 * @param string $orderby
	 * @param int $limit
	 * @param int $pagesize
	 * @param int $page
	 * @return array
	 */
	 public static function getList(array $where = [], array $field = ['*'], string $groupby = '', string $orderby = '', int $limit = 0, int $pagesize = 10, int $page = 0): array
	 {
	    global $empire, $dbtbpre;

		['where' => $str_where, 'data' => $data] = static::parseWhere($where, false);

		$get_field  = [];
		$arr_where 	= [
			'pri'		=> [],
			'sec'		=> []
		];

		if (['*'] !== $field && count($data) > 0) {

			$where_field	= array_keys($data);
			$arr_where		= [
				'pri'	=> array_filter(static::FIELD['pri'], fn($item) => in_array($item, $where_field)),
				'sec'	=> array_filter(static::FIELD['sec'], fn($item) => in_array($item, $where_field))
			];
		}

		$str_group	= null === $groupby || '' === $groupby ? '' : ' GROUP BY ' . $groupby;
		$str_order	= null === $orderby || '' === $orderby ? '' : ' ORDER BY ' . $orderby;
		$str_limit 	= 0 === $limit && 0 === $pagesize ? '' : ($limit > 0 ? ' LIMIT ' . $limit : ' LIMIT ' . ($page * $pagesize) . ',' . $pagesize);

		$option = [];
		foreach(static::TABLE as $t => $table) {

			$get_field  = ['*'] === $field ? static::FIELD[$t] : array_intersect(static::FIELD[$t], $field);
			$count      = count($get_field);

			if (['*'] === $field || $count > 1 || (1 === $count && [static::PRIMARY] !== $get_field) || (count($arr_where[$t]) > 0 && [static::PRIMARY] !== $arr_where[$t])) {

				$option[$t] = [
				    'field'     => $get_field,
				    'table'     => $dbtbpre . $table,
				    'where'     => $str_where,
					'group'		=> $str_group,
				    'order'     => $str_order,
				    'limit'     => $str_limit
				];
			}
		}

		$res = [];
		//主表
		if (isset($option['pri']) && !isset($option['sec'])) {

			$sql = sprintf('SELECT %s FROM %s%s%s%s%s',
				'`' . implode('`,`', $option['pri']['field']) . '`',
				$option['pri']['table'],
				$option['pri']['where'],
				$option['pri']['group'],
				$option['pri']['order'],
				$option['pri']['limit']
			);
		}
		//副表
		elseif (!isset($option['pri']) && isset($option['sec'])) {

			$sql = sprintf('SELECT %s FROM %s%s%s%s%s',
				'`' . implode('`,`', $option['sec']['field']) . '`',
				$option['sec']['table'],
				$option['sec']['where'],
				$option['sec']['group'],
				$option['sec']['order'],
				$option['sec']['limit']
			);
		}
		//并表
		else{

			$sql = sprintf(
				'SELECT %s FROM `%s` AS a INNER JOIN `%s` AS b ON %s%s%s%s%s',
				'a.`' . implode('`,a.`', $option['pri']['field']) . '`' . ',b.`' . implode('`,b.`', array_diff($option['sec']['field'], [static::PRIMARY])) . '`',
				$option['pri']['table'],
				$option['sec']['table'],
				'a.`' . static::PRIMARY . '` = b.`' . static::PRIMARY . '`',
				count($data) > 0 ? static::addPrefix($option['pri']['where']) : '',
				$option['pri']['group'] ? static::addPrefix($option['pri']['group']) : '',
				$option['pri']['order'] ? static::addPrefix($option['pri']['order']) : '',
				$option['pri']['limit']
			);
		}

		$sql = $empire->query($sql);

		if(0 < $num = $empire->num1($sql)){

			while($r = $empire->fetch($sql)){
				//去数字键
				$res[] = array_filter($r, fn($key) => is_string($key), ARRAY_FILTER_USE_KEY);
			}
		}

	    return $res;
	 }

	 /**
	 * 插入交易信息
	 *
	 * @param array $add
	 * @param string $type
	 * @return int 0为失败，成功返回当前id
	*/
	public static function insert(array $add = [], string $type = ''): int
	{
		global $empire, $dbtbpre;

	    $insert = static::MYDEFAULT;
		array_walk($insert, function(&$value, $key) use($add) {

			// 分组
			$value  = array_filter($value, fn($item) => in_array($item, static::FIELD[$key]), ARRAY_FILTER_USE_KEY);

			$add    = array_filter($add, fn($item) => in_array($item, static::FIELD[$key]), ARRAY_FILTER_USE_KEY);
			// 更新
			$value 	= array_replace($value, $add);
		});

	    // 移除id, 自动增长
	    if (!isset($add['id'])) unset($insert['index']['id']);

		// 主表
		$data 	= self::parseInsert($insert['pri']);
	    $sql 	= sprintf('INSERT INTO %s(%s) VALUES(%s)', $dbtbpre . static::TABLE['pri'], $data['key'], $data['value']);
		$sqlpri = $empire->query($sql);

		$lastid = $empire->lastid();

		// 副表
		$insert['sec'][static::PRIMARY] = $lastid;
		$data 	= static::parseInsert($insert['sec']);
		$sql 	= sprintf('INSERT INTO %s(%s) VALUES(%s)', $dbtbpre . static::TABLE['sec'], $data['key'], $data['value']);
		$sqlsec = $empire->query($sql);

	    // 更新失败
	    if (!$sqlpri || !$sqlsec) $lastid = 0;

		return $lastid;
	}

	/**
	 * 更新数据
	 *
	 * @param array $where
	 * @param array $add
	 * @param int $limit
	 * @param string $type
	 * @return bool
	 **/
	public static function update(array $where = [], array $add = [], int $limit = 0, string $type = ''): bool
	{
	    global $empire, $dbtbpre;

	    ['where' => $str_where] = static::parseWhere($where, false);

	     // 去null值, 0值或负值不能去，
	    $add    = array_filter($add, fn($item) => null !== $item && !empty($item));

	    // 找出要新字段进行更新
	    $field  = array_keys($add);

		$sqlpri = $sqlsec = false;
        $limit  = $limit ? ' LIMIT ' . $limit : '';

	    // 更新主表
	    $update = array_intersect(static::FIELD['pri'], $field);
	    if (!empty($update)) {

	        $put_data   = array_filter($add, fn($item) => in_array($item, $update), ARRAY_FILTER_USE_KEY);
	       	$sql        = sprintf('UPDATE %s SET %s%s%s', $dbtbpre . static::TABLE['pri'], static::parseUpdate($put_data), $str_where, $limit);
	        $sqlpri     = $empire->query($sql);
	    }

	    // 更新副表
	    $update = array_intersect(static::FIELD['sec'], $field);
	    if (!empty($update)) {

	        $put_data   = array_filter($add, fn($item) => in_array($item, $update), ARRAY_FILTER_USE_KEY);
	        $sql        = sprintf('UPDATE %s SET %s%s%s', $dbtbpre . static::TABLE['sec'], static::parseUpdate($put_data), $str_where, $limit);
	        $sqlsec     = $empire->query($sql);
	    }

	    return false !== $sqlpri || false !== $sqlsec;
	}

	/**
	 * 联表名增加前缀
	 *
	 * @param string $str
	 * @return string
	 */
	private static function addPrefix(string $str): string
	{
		foreach (static::FIELD['pri'] as $field) {

			if (str_contains($str, '`' . $field . '`')) $str = str_replace('`' . $field . '`', 'a.`' . $field . '`', $str);
		}

		foreach (static::FIELD['sec'] as $field) {

			if ($field !== static::PRIMARY && str_contains($str, '`' . $field . '`')) $str = str_replace('`' . $field . '`', 'b.`' . $field . '`', $str);
		}

		return $str;
	}
}
